﻿using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.Linq;
using System.Reflection;
using System.Web.Security;
using RedRiver.Framework.Web.Models;

namespace RedRiver.Framework.Web.Security{
    public static class ADMembershipHelper{
        /// <summary>
        /// 公司名称
        /// </summary>
        public static string CompanyName { get; set; }

        /// <summary>
        /// 部门OU
        /// </summary>
        public static string OUDepartments { get; set; }

        /// <summary>
        /// 更新用户 DirectoryEntry 信息
        /// </summary>
        /// <param name="userName"></param>
        /// <param name="employee"></param>
        public static void UpdateUserDirectoryEntry(string userName, Employee employee){
            IEnumerable<ActiveDirectoryMembershipProvider> providers =
                Membership.Providers.OfType<ActiveDirectoryMembershipProvider>();
            if (providers.Any()){
                ActiveDirectoryMembershipProvider adProvider = providers.First();
                FieldInfo adConnField = adProvider.GetType().GetField("adConnectionString",
                                                                      BindingFlags.Instance | BindingFlags.NonPublic |
                                                                      BindingFlags.GetField);
                if (adConnField != null){
                    string adConnectionString = adConnField.GetValue(adProvider).ToString();
                    DirectoryEntry ou = null;
                    try{
                        ou = new DirectoryEntry(adConnectionString);
                        var searcher = new DirectorySearcher(ou, "(&(CN=" + userName + ")(objectClass=user))");
                        SearchResult result = searcher.FindOne();
                        if (result == null){
                            return;
                        }
                        DirectoryEntry user = result.GetDirectoryEntry();//ou.Children.Find("cn=" + userName); //在用户对象创建zixian用户
                        user.UsePropertyCache = true;
                        user.InvokeSet("company", CompanyName);
                        user.InvokeSet("department", employee.DepName);
                        user.InvokeSet("c", "CN");
                        user.InvokeSet("sn", employee.FullName.Substring(0, 1));
                        user.InvokeSet("givenName", employee.FullName.Substring(1));
                        user.InvokeSet("displayName", employee.FullName);
                        user.InvokeSet("description", employee.DepName + " - " + employee.FullName);
                        user.CommitChanges();
                        DirectoryEntry depEntry = GetDepartmentEntry(ou.Parent, employee.DepName);
                        if (depEntry != null){
                            depEntry.Invoke("Add", user.Path);
                            depEntry.CommitChanges();
                            depEntry.Close();
                        }
                    } finally{
                        if (ou != null){
                            ou.Close();
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 获取部门用户组,如果改组不存在,则在 OU=Departments 组织下新建一个用户组
        /// </summary>
        /// <param name="root"></param>
        /// <param name="depName"></param>
        /// <returns></returns>
        private static DirectoryEntry GetDepartmentEntry(DirectoryEntry root, string depName){
            var searcher =
                new DirectorySearcher(root, "(&(CN=" + depName + ")(objectClass=group))");
            SearchResult result = searcher.FindOne();
            if (result != null){
                return result.GetDirectoryEntry();
            }
            DirectoryEntry deps;
            try{
                deps = root.Children.Find(OUDepartments, "organizationalUnit");
            } catch (Exception){
                //建立部门组织
                deps = root.Children.Add(OUDepartments, "organizationalUnit");
                deps.CommitChanges();
            }

            DirectoryEntry dep = deps.Children.Add("CN=" + depName, "group");
            dep.InvokeSet("sAMAccountName", depName);
            dep.CommitChanges();
            return dep;
        }
    }
}